/**
 * Copyright (c) 2024-2025 National Fundamental Software of China Co., Ltd.
 *
 * You should have find a copy of NFSChina License. If not, please contact us
 * by email <os_support@nfschina>
 *
**/

/*
    Plasma analog-clock drawing code:

    SPDX-FileCopyrightText: 1998 Luca Montecchiani <m.luca@usa.net>
    SPDX-FileCopyrightText: 2007 Aaron Seigo <aseigo@kde.org>
    SPDX-FileCopyrightText: 2007 Riccardo Iaconelli <riccardo@kde.org>

    SPDX-License-Identifier: GPL-2.0-or-later
*/

#include "dtime.h"

#include <stdlib.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include "helper.h"
#include <QGroupBox>
#include <QPainter>
#include <QPushButton>
#include <QTimeEdit>

#include <KColorScheme>
#include <KConfig>
#include <KGlobal>
#include <KMessageBox>
#include <KProcess>
#include <KSystemTimeZone>
#include <KTreeWidgetSearchLine>
#include <QDebug>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <Plasma/Svg>
#include<QStackedWidget>
#include "timedated_interface.h"
#include "switchButton.h"

Dtime::Dtime(QWidget *parent, bool haveTimeDated)
    : QWidget(parent)
    , m_haveTimedated(haveTimeDated)
    ,m_ischecked(true)
{
    setupUi(this);

    //添加switch
    setDateTimeAuto = new SlipButton(frame);
    setDateTimeAuto->setGeometry(492, 15, 36, 20);

    setDateFormat = new SlipButton(frame_3);
    setDateFormat->setGeometry(492, 15, 36, 20);

    setDateFormat->setChecked(true);

    connect(setDateTimeAuto, &SlipButton::toggled, this, &Dtime::serverTimeCheck);
    connect(setDateTimeAuto, &SlipButton::toggled, this, &Dtime::configChanged);

    //updateConfigFile(true);
    load();

    connect(setDateFormat, &SlipButton::toggled,
            [=](bool checked)
    {
//        //updateConfigFile(checked);
//        if(m_use24hFormat != checked){
//            m_use24hFormat = checked;
//            m_isDateFormatDirty = true;
//            updateHourFormat();
//            Q_EMIT FormatconfigChanged(true);
//        }
        m_ischecked = setDateFormat->isChecked();
        //updateConfigFile(checked);
        m_use24hFormat = checked;
        updateHourFormat(); // 更新小时选项
        // 立即强制更新时间显示
        //QTimer::singleShot(0, this, &Dtime::timeout);
        Q_EMIT FormatconfigChanged(true);
    }
    );

    timeServerList->setEditable(false);
    connect(timeServerList, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &Dtime::configChanged);
    connect(timeServerList, &QComboBox::editTextChanged, this, &Dtime::configChanged);
    connect(setDateTimeAuto, &SlipButton::toggled, timeServerList, &QComboBox::setEnabled);
    connect(amAndPm, QOverload<int>::of(&QComboBox::currentIndexChanged), this,  [ = ](){
        timeChanged(m_initialAmAndPm == amAndPm->currentIndex());
    });

    timeServerList->setEnabled(false);
    timeServerList->setEditable(true);

    if (!haveTimeDated) {
        findNTPutility();
        if (ntpUtility.isEmpty()) {
            QString toolTip = i18n(
                "No NTP utility has been found. "
                "Install 'ntpdate' or 'rdate' command to enable automatic "
                "updating of date and time.");
            setDateTimeAuto->setEnabled(false);
            setDateTimeAuto->setToolTip(toolTip);
            timeServerList->setToolTip(toolTip);
        }
    }



    updateHourFormat();


    connect(yearbox, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &Dtime::changeDate);
    connect(monthbox, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &Dtime::changeDate);
    connect(daybox, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &Dtime::changeDate);

    connect(yearbox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &Dtime::onYearChanged);
    connect(monthbox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &Dtime::onMonthChanged);
    connect(daybox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &Dtime::onDayChanged);




    connect(hourbox, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &Dtime::set_time);
    connect(minutebox,static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &Dtime::set_time);
    connect(secondbox, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, &Dtime::set_time);
    connect(&internalTimer, &QTimer::timeout, this, &Dtime::timeout);


    connect(setDateTimeAuto, &SlipButton::toggled, this, &Dtime::setAutoCheck);


    bool isAuto = setDateTimeAuto->isChecked();
    qDebug() << "_____________________________________" << isAuto ;
    yearbox->setEnabled(!isAuto);
    monthbox->setEnabled(!isAuto);
    daybox->setEnabled(!isAuto);
    hourbox->setEnabled(!isAuto);
    minutebox->setEnabled(!isAuto);
    secondbox->setEnabled(!isAuto);
    amAndPm->setEnabled(!isAuto);
}

void Dtime::updateConfigFile(bool use24hFormat)
{
    KSharedConfig::Ptr config = KSharedConfig::openConfig("ktimezonedrc");
    KConfigGroup containmentGroup = config->group("TimeZones");
    qDebug() << "use24hFormat" << use24hFormat;
    containmentGroup.writeEntry("use24hFormat", m_ischecked ? 2 : 0, KConfigBase::Notify); // Default to 24-hour format
    config->sync();
}


void Dtime::serverTimeCheck()
{
    bool enabled = ntpUtility.isEmpty() || !setDateTimeAuto->isChecked();
    yearbox->setEnabled(enabled);
    monthbox->setEnabled(enabled);
    daybox->setEnabled(enabled);
    hourbox->setEnabled(enabled);
    minutebox->setEnabled(enabled);
    secondbox->setEnabled(enabled);
    amAndPm->setEnabled(enabled);
}

void Dtime::findNTPutility()
{
    QByteArray envpath = qgetenv("PATH");
    if (!envpath.isEmpty() && envpath.startsWith(':')) {
        envpath.remove(0, 1);
    }

    QStringList path = {"/sbin", "/usr/sbin"};
    if (!envpath.isEmpty()) {
        path += QFile::decodeName(envpath).split(QLatin1Char(':'));
    } else {
        path += {"/bin", "/usr/bin"};
    }

    const auto possible_ntputilities = {"ntpdate", "rdate"};
    for (const QString &possible_ntputility : possible_ntputilities) {
        ntpUtility = QStandardPaths::findExecutable(possible_ntputility, path);
        if (!ntpUtility.isEmpty()) {
            qDebug() << "ntpUtility = " << ntpUtility;
            return;
        }
    }

    qDebug() << "ntpUtility not found!";
}

void Dtime::set_time()
{
    if (ontimeout)
        return;
    internalTimer.stop();
    Q_EMIT timeChanged(true);
    configChanged();
}


void Dtime::configChanged()
{
    Q_EMIT timeChanged(true);
    saveConfig();
}
void Dtime::changeDate()
{
    if (ontimeout)
        return;
    internalTimer.stop();
    Q_EMIT timeChanged(true);
    configChanged();
}

void Dtime::updateHourFormat()
{
    // 根据 setDateFormat 的状态设置小时框的格式
    if (m_use24hFormat) {
        // 24 小时格式
        hourbox->clear();
        for (int hour = 0; hour < 24; ++hour) {
            hourbox->addItem(QString::number(hour).rightJustified(2, '0'));
        }
    } else {
        // 12 小时格式
        hourbox->clear();
        for (int hour = 1; hour <= 12; ++hour) {
            hourbox->addItem(QString::number(hour).rightJustified(2, '0'));
        }
    }

    amAndPm->setVisible(!m_use24hFormat);

    // 获取当前时间并转换为对应格式的小时
    QTime currentTime = QTime::currentTime();
    int hour = currentTime.hour();
    if (!m_use24hFormat) {
        amAndPm->setCurrentIndex(hour > 12 || hour == 0);
        m_initialAmAndPm = amAndPm->currentIndex();

        // 转换为12小时制（1-12）
        hour = (hour % 12 == 0) ? 12 : hour % 12;
    }
    QString hourText = QString("%1").arg(hour, 2, 10, QLatin1Char('0'));
    int hourIndex = hourbox->findText(hourText);
    if (hourIndex != -1) {
        hourbox->setCurrentIndex(hourIndex);
    }
}

void Dtime::load()
{
    KSharedConfig::Ptr config = KSharedConfig::openConfig("ktimezonedrc");
    KConfigGroup containmentGroup = config->group("TimeZones");

    int use24hFormat = containmentGroup.readEntry("use24hFormat", 0);

    // 写入缺失的配置项
    if (!containmentGroup.hasKey("use24hFormat")) {
        containmentGroup.writeEntry("use24hFormat", 2, KConfigBase::Notify);
        config->sync();
    }

    setDateFormat->setChecked(use24hFormat > 0);
    m_ischecked = setDateFormat->isChecked();

    m_use24hFormat = (use24hFormat == 2);
    m_isDateFormatDirty = false;

    updateHourFormat();


    if (m_haveTimedated) {
        OrgFreedesktopTimedate1Interface timeDatedIface(QStringLiteral("org.freedesktop.timedate1"),
                                                        QStringLiteral("/org/freedesktop/timedate1"),
                                                        QDBusConnection::systemBus());
        timeServerList->setVisible(false);
        timeServerLabel->setVisible(false);
        setDateTimeAuto->setEnabled(timeDatedIface.canNTP());
        setDateTimeAuto->setChecked(timeDatedIface.nTP());
    } else {
        KConfig _config(QStringLiteral("kcmclockrc"), KConfig::NoGlobals);
        KConfigGroup config(&_config, "NTP");
        timeServerList->clear();
        timeServerList->addItems(config
                                     .readEntry("servers", i18n("Public Time Server (pool.ntp.org),\
        asia.pool.ntp.org,\
        europe.pool.ntp.org,\
        north-america.pool.ntp.org,\
        oceania.pool.ntp.org"))
                                     .split(',', Qt::SkipEmptyParts));
        setDateTimeAuto->setChecked(config.readEntry("enabled", false));
        if (ntpUtility.isEmpty()) {
            timeServerList->setEnabled(false);
        }

    }

    // Reset to the current date and time
    time = QTime::currentTime();
    date = QDate::currentDate();

    // Date
    for (int year = 1900; year <= 2100; ++year) {
        yearbox->addItem(QString::number(year));
    }
    for (int month = 1; month <= 12; ++month) {
        monthbox->addItem(QString::number(month).rightJustified(2, '0'));
    }
    yearbox->setCurrentIndex(yearbox->findText(QString::number(date.year())));
    monthbox->setCurrentIndex(monthbox->findText(date.toString("MM")));
    updateDays(date.year(), date.month());
    daybox->setCurrentIndex(daybox->findText(date.toString("dd")));


    // Time

//    for (int hour = 0; hour < 24; ++hour) {
//        hourbox->addItem(QString::number(hour).rightJustified(2, '0'));
//    }
    int hour = time.hour();
    if (!m_use24hFormat) {
        hour = (hour % 12 == 0) ? 12 : hour % 12;
    }
    QString hourText = QString("%1").arg(hour, 2, 10, QLatin1Char('0'));
    for (int minute = 0; minute < 60; ++minute) {
        minutebox->addItem(QString::number(minute).rightJustified(2, '0'));
    }
    for (int second = 0; second < 60; ++second) {
        secondbox->addItem(QString::number(second).rightJustified(2, '0'));
    }
    hourbox->setCurrentIndex(hourbox->findText(time.toString("hh")));
    minutebox->setCurrentIndex(minutebox->findText(time.toString("mm")));
    secondbox->setCurrentIndex(secondbox->findText(time.toString("ss")));

    // start internal timer
    internalTimer.start(1000);
    timeout();


    Q_EMIT timeChanged(false);

    m_initialNtpEnabled = setDateTimeAuto->isChecked();
    m_initialUserTime = userTime();
    m_initialUse24hFormat = m_use24hFormat;
}

bool Dtime::hasTimeOrNtpChanges() const {
    return (m_initialNtpEnabled != ntpEnabled()) || (m_initialUserTime != userTime());
}

bool Dtime::hasDateFormatChanges() const {
    return m_initialUse24hFormat != m_use24hFormat;
}

void Dtime::processHelperErrors(int code)
{
    if (code & ClockHelper::NTPError) {
        KMessageBox::error(this, i18n("Unable to contact time server: %1.", timeServer));
        setDateTimeAuto->setChecked(false);
    }
    if (code & ClockHelper::DateError) {
        KMessageBox::error(this, i18n("Can not set date."));
    }
    if (code & ClockHelper::TimezoneError)
        KMessageBox::error(this, i18n("Error setting new time zone."), i18n("Time zone Error"));
}

void Dtime::saveConfig()
{
    KSharedConfig::Ptr config = KSharedConfig::openConfig("ktimezonedrc");
    KConfigGroup containmentGroup = config->group("TimeZones");

    // 根据 setDateFormat 的状态保存 use24hFormat 的值
    bool use24hFormat = setDateFormat->isChecked();
    containmentGroup.writeEntry("use24hFormat", use24hFormat ? 2 : 0, KConfigBase::Notify); // 2 表示 24 小时制，0 表示 12 小时制
    config->sync(); // 确保配置文件被同步
}

void Dtime::timeout()
{
    time = QTime::currentTime();
    date = QDate::currentDate();

    ontimeout = true;
    yearbox->setCurrentIndex(yearbox->findText(QString::number(date.year())));
    monthbox->setCurrentIndex(monthbox->findText(date.toString("MM")));
    daybox->setCurrentIndex(daybox->findText(date.toString("dd")));

    // 处理小时显示，根据当前时间格式转换
    int hour = time.hour();
    if (!m_use24hFormat) {
        hour = (hour % 12 == 0) ? 12 : hour % 12;
    }
    QString hourText = QString("%1").arg(hour, 2, 10, QLatin1Char('0'));
    hourbox->setCurrentIndex(hourbox->findText(hourText));

    minutebox->setCurrentIndex(minutebox->findText(time.toString("mm")));
    secondbox->setCurrentIndex(secondbox->findText(time.toString("ss")));
    ontimeout = false;
}

void Dtime::updateDays(int year, int month) {
    int daysInMonth = QDate(year, month, 1).daysInMonth();
    int cindex = daybox->currentIndex();
    daybox->clear();
    for (int day = 1; day <= daysInMonth; ++day) {
        daybox->addItem(QString::number(day).rightJustified(2, '0'));
    }
    daybox->setCurrentIndex(qMin(cindex, daysInMonth - 1));
}


void Dtime::onYearChanged(int index) {
    int year = yearbox->itemText(index).toInt();
    int month = monthbox->currentIndex() + 1;
    updateDays(year, month);
}

void Dtime::onMonthChanged(int index) {
    int year = yearbox->itemText(yearbox->currentIndex()).toInt();
    int month = index + 1;
    updateDays(year, month);
}

void Dtime::onDayChanged(int index) {
    int day = daybox->itemText(index).toInt();
    qDebug() << "Selected Day:" << day;
}


QStringList Dtime::ntpServers() const
{
    QStringList list;
    if (timeServerList->count() != 0)
        list.append(timeServerList->currentText());
    for (int i = 0; i < timeServerList->count(); i++) {
        QString text = timeServerList->itemText(i);
        if (!list.contains(text))
            list.append(text);
        if (list.count() == 10)
            break;
    }
    return list;
}

bool Dtime::ntpEnabled() const
{
    return setDateTimeAuto->isChecked();
}

QDateTime Dtime::userTime() const
{
    int year = yearbox->currentText().toInt();
    int month = monthbox->currentText().toInt();
    int day = daybox->currentText().toInt();
    int hour = hourbox->currentText().toInt() + (12 * amAndPm->currentIndex());
    int minute = minutebox->currentText().toInt();
    int second = secondbox->currentText().toInt();

    QDate date(year, month, day);
    QTime time(hour, minute, second);
    return QDateTime(date, time);
}

QString Dtime::quickHelp() const
{
    return i18n(
        "<h1>Date & Time</h1> This system settings module can be used to set the system date and"
        " time. As these settings do not only affect you as a user, but rather the whole system, you"
        " can only change these settings when you start the System Settings as root. If you do not have"
        " the root password, but feel the system time should be corrected, please contact your system"
        " administrator.");
}

void Dtime::setAutoCheck()
{
    bool enabled = setDateTimeAuto->isChecked();
    yearbox->setDisabled(enabled);
    monthbox->setDisabled(enabled);
    daybox->setDisabled(enabled);
    hourbox->setDisabled(enabled);
    minutebox->setDisabled(enabled);
    secondbox->setDisabled(enabled);
    amAndPm->setDisabled(enabled);
}
